// 5-1 多线程处理-实例
/**
 * C++ 多线程
 * 多线程是多任务处理的一种特殊形式，多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下，两种类型的多任务处理：基于进程和基于线程。

      **基于进程**的多任务处理是**程序的并发执行**。
      **基于线程****的多任务处理是**同一程序的片段的并发执行**。

 * 多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程，每个线程定义了一个单独的执行路径。

 * 本教程假设您使用的是 Linux 操作系统，我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用，比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。

 *
 *
 * 创建线程
 * 下面的程序，我们可以用它来创建一个 POSIX 线程：

        #include <pthread.h>
        pthread_create (thread, attr, start_routine, arg) 

 * 在这里，pthread_create 创建一个新的线程，并让它可执行。下面是关于参数的说明：

      参数	        描述
      thread	      指向线程标识符指针。
      attr	        一个不透明的属性对象，可以被用来设置线程属性。您可以指定线程属性对象，也可以使用默认值 NULL。
      start_routine	线程运行函数起始地址，一旦线程被创建就会执行。
      arg	          运行函数的参数。它必须通过把**引用作为指针强制转换为 void 类型**进行传递。如果没有传递参数，则使用 NULL。
 
 * 创建线程成功时，函数返回 0，若返回值不为 0 则说明创建线程失败。
 *
 * 
 * 终止线程
 * 使用下面的程序，我们可以用它来终止一个 POSIX 线程：

        #include <pthread.h>
        pthread_exit (status) 

 * 在这里，pthread_exit 用于显式地退出一个线程。通常情况下，pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。

 * 如果 main() 是在它所创建的线程之前结束，并通过 pthread_exit() 退出，那么其他线程将继续执行。否则，它们将在 main() 结束时自动被终止。
 *
 * ----#1 start----------
 * #1实例一 创建5个线程，输出Hello Runoob！
 * 使用 -lpthread 库编译下面的程序：

      $ g++ test.cpp -lpthread -o test.o

 * 现在，执行程序

      $ ./test.o

 * ----#1 end---------- 
 * 
 * ----#2 start----------
 * #2实例二
 * 以下简单的实例代码使用 pthread_create() 函数创建了 5 个线程，并接收传入的参数。每个线程打印一个 "Hello Runoob!" 消息，并输出接收的参数，然后调用 pthread_exit() 终止线程。
 * ----#2 end----------
*/

#include <iostream>
#define __mark 1

/**
 * #1 实例1
 * 编译 g++ 5_1.cpp -lpthread -o ./build/5_1.o
 * 执行程序 5_1.o
*/
#if 1 == __mark
#include <pthread.h>
#include <unistd.h>
// 线程运行的函数
void *threadMehthod(void *args)
{
  static int id = 0;
  id++;
  const int a = id;

  std::cout << "Hello Runoob! Thread " << a << " " << std::endl;
  while (1)
  {
    std::cout << "Thread " << a << std::endl;
    sleep(a);
  }

  return 0;
}
int main(void)
{
  const int size = 5;
  // 定义线程的id变量,多个变量使用数组保存
  pthread_t tids[size];
  for (int i = 0; i < size; i++)
  {
    // 参数依次是: 创建的线程id，线程参数，调用的函数，传入的函数参数
    int ret = pthread_create(&tids[i], NULL, threadMehthod, NULL);
    if (ret != 0)
    {
      std::cout << "pthread create error;error code : " << ret << std::endl;
    }
  }
  // 等各个线程退出后。进程才结束，否则进程强制结束了，线程可能还没反应过来
  pthread_exit(NULL);
  printf("---------------------end---------------\n");
  return 0;
}
/**
 * #2 实例二
 * 编译 g++ 5_1.cpp -lpthread -o ./build/5_1.o
*/
#elif 2 == __mark
#include <pthread.h>
void *thread_func(void *argv)
{
  // 无类型指针转化为int *，再取值
  int tid = *((int *)argv);
  std::cout << "HELLO RUNOOB!"
            << " Thread " << tid << std::endl;

  pthread_exit(NULL);
  return 0;
}
int main(void)
{
  const int size = 5;
  pthread_t threads[size];
  int argvs[size];
  for (int i = 0; i < size; i++)
  {
    argvs[i] = i + 1;
    // 传入的时候转化成void *指针，即无类型指针，不过不转也行，函数参数有隐式类型转换
    int res = pthread_create(&threads[i], NULL, thread_func, (void *)&argvs[i]);
    if (0 != res)
    {
      std::cerr << "create thread error;error code : " << res << std::endl;
      exit(-1);
      // exit(EXIT_FAILURE);
    }
  }
  pthread_exit(NULL);
  printf("---------------------end---------------\n");
  return 0;
}
#endif
